import time
from collections import deque
from utils import seconds_to_time_format


class Progress:
    BAR_LENGTH = 20
    BAR_ITEMS = '▏▎▍▌▋▊▉'
    BAR_ITEMS_LEN = len(BAR_ITEMS)

    def __init__(self, total, step, avg_base_time_num=500):
        self.total = total
        self.step = step
        self.current = 0
        self.last_update = time.time()
        self.elapsed_time = 0
        self.elapsed_time_deque = deque(maxlen=avg_base_time_num)

    def show(self, message, end=""):
        percent = self.current / self.total
        bar_fill = round(percent * self.BAR_LENGTH * self.BAR_ITEMS_LEN) - 1
        fill = "" if bar_fill == -1 else (bar_fill // self.BAR_ITEMS_LEN) * self.BAR_ITEMS[-1] + self.BAR_ITEMS[bar_fill % self.BAR_ITEMS_LEN]
        empty = (self.BAR_LENGTH - len(fill)) * " "
        bar = fill + empty
        percent_str = (str(round(percent * 100, 10)) + "00000")[:5]
        avg_time = sum(self.elapsed_time_deque) / len(self.elapsed_time_deque)
        remaining_time = avg_time * (self.total - self.current)
        elapsed_time_format = seconds_to_time_format(self.elapsed_time)
        remaining_time_format = seconds_to_time_format(remaining_time)
        one_second_count = 0 if avg_time == 0 else round(1 / avg_time, 2)
        print_str = f"{percent_str}%|{bar}| {self.current}/{self.total} [{elapsed_time_format}<{remaining_time_format}, {one_second_count}it/s]"
        if message:
            print_str += f" Message={message}"
        if self.step != 0 and self.current % self.step == 0:
            end = '\n'
        print(f"\r{print_str}", end=end, flush=True)

    def update(self, num=1, message=None):
        current_time = time.time()
        elapsed_time = current_time - self.last_update
        self.last_update = current_time
        self.elapsed_time_deque.append(elapsed_time)
        self.elapsed_time += elapsed_time
        self.current += num
        self.show(message)

    def set_message(self, message):
        self.show(message, end="\n")


if __name__ == '__main__':
    p = Progress(102400, 1000)
    for i in range(102400):
        # print(f"\r{i}", end="", flush=True)
        p.update()

